//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) 1995-2003  Microsoft Corporation

Module Name: chanel.h

Abstract:


Notes:


--*/
//
//
// (C) Copyright 2007 Marvell International Ltd.
//  All Rights Reserved
//

#pragma once

//
// OS side interface
//

#include <windows.h>

// power management
#include <winioctl.h>
#include <pm.h>

#include "dispatcher.h"

// registry key
#define GSM710_CHANNEL_ID                      TEXT("GSM_0710_DLCI")
#define GSM710_CHANNEL_TYPE                    TEXT("GSM_0710_TYPE")
#define GSM710_CHANNEL_ACTIVITY_TIMEOUT        TEXT("GSM_0710_ACTIVITY_TIMEOUT")

// channel states
enum tChnlState
{
    DISCONNECTED,
    CONNECTED,

    MAX_CHNL_STATE
};

#define REC_BUFFER_SIZE     (1024 * 5)

//====================================================================================================
// generic Channel Class
//====================================================================================================

class CChanel
{
public :
    CChanel(BYTE bDlci, LPTHREAD_START_ROUTINE ProtocolTh, bool (*pDerivedClassTerminate) (PVOID)) ;
    ~CChanel() ;

    virtual bool Init() ;
    virtual void Terminate() ;

    bool operator!() ;

    // GSM 07.10 
    //-----------
    LONG m_lState ;

    inline BYTE GetDLCI() { return (m_bAddress >> 2) ; } ;

    // sending frame
    void SendUA() ;
    void SendDM() ;

    bool SendSABM() ;
    bool SendDISC() ;
    DWORD SendUIH(BYTE *pInBuf, DWORD dwLen, BYTE bUIHControl = (CTRL_FIELD_UIH & CLEAR_PF_MASK)) ;   

    inline DWORD MaxFrameData() {return m_cbMaxFrameData; }

    // receiving frame    
    inline DWORD RecBufSize() {return m_cbRecBuf; }

    // CChanel / CDispatcher communication logic
    void SignalEndOfFrame(BYTE bControl, BYTE* pData, DWORD cbData) ;
    virtual void SetModemStatus(BYTE v24Sig);

    wchar_t* m_pName ;
    bool m_bTerminate ;

protected:
    bool m_bIsOk ;
  
    BYTE m_bAddress;

    //Receive
    BYTE m_bControl;
    BYTE m_bUIHControl;

    BYTE* m_pRec;
    DWORD m_cbRecBuf;
    BYTE* m_pRead;
    BYTE* m_pWrite;
    CRITICAL_SECTION m_csReadLocker;

    // flow control
    static HANDLE s_hFCONEv ;

    // CRC
    //-----
    static unsigned char s_ucCrcTbl[256] ;
    inline BYTE CalcFCS(BYTE* pBuf, DWORD cbBuf);

    // serial line
    //-------------
    HANDLE m_hProtocolTh;
    HANDLE m_hEndOfFrameEv;
    HANDLE m_hRespEv ;

    virtual void SignalData();

    // underlying COM
    //----------------
    static CDispatcher s_Dispatcher ;

private:

    LPTHREAD_START_ROUTINE m_ProtocolTh ;

    //Send
    BYTE m_bFrameFlag;    
    BYTE* m_pSend;    
    DWORD m_cbMaxFrameData;
    CRITICAL_SECTION m_csSendLocker;
    
    typedef struct
    {
        BYTE Header[2];
        BYTE *pData;
        DWORD cbData;
    } tFrameData;

    BOOL (CChanel::* m_pfnSend) (tFrameData* pFrameData);
    BOOL AdvancedModeSend (tFrameData* pFrameData);
    BOOL BasicModeSend (tFrameData* pFrameData);

    bool SendFrameWaitAck (BYTE bControl);

    CRITICAL_SECTION m_csPollFrameLocker;

    //Buffer used for send and receive
    BYTE* m_pDataBuf;
    
    // derived class specific
    //------------------------
    bool (*m_pDerivedClassTerminate) (PVOID) ;

    // Rem :
    //    - the channel threads (UserChannelTh, CtrlChannelTh) are a friend routine 
    //      of the relevant derived class because call to derived class specific methods
    //      are direct and not done through pointer to routine, which saves time
};

//====================================================================================================
// User Channel Class
//====================================================================================================
enum tActivityStatus
{
    ACTIVITY_NO_REPORT = 0,

    CHANNEL_OPEN,
    CHANNEL_CLOSE,
    CHANNEL_IDLE,
    CHANNEL_BUSY
} ;

class CUserChanel : public CChanel
{
public :
    CUserChanel(BYTE bDlci, bool bIsATChnl, DWORD dwActivityTimeOut, const wchar_t *pName) ;
    ~CUserChanel() ;

    bool Init() ;

    // Monitor Activity
    //-------------------
    void NotifyIdle();
    void NotifyBusy();

    //Modem status
    void SetModemStatus(BYTE v24Sig);
    bool SendModemStatus(DWORD dwCode);
    DWORD GetModemStatus();
    bool m_bInitFlag;

protected:
    void SignalData();

private:

    // init/terminate
    //----------------
    friend bool UserChnlTerminate(PVOID lpParameter) ;

    // GSM 07.10
    //-----------
    bool m_bATChnl ;
    // protocol thread
    friend DWORD WINAPI UserChannelTh( PVOID pContext ) ;

    // serial line
    //-------------
    ULONG m_fEventMask;
    ULONG m_fEventData;
    bool m_fAbort;
    HANDLE m_hCommEvent ;
    
    // power management
    //-------------------
    CEDEVICE_POWER_STATE m_eLastPowerState ;

    // Monitor Activity
    //-------------------
    bool m_bMonitorActivity ;
    DWORD m_dwActivityTimeOut ;
    LONG m_lLastActivityReport;
    LONG m_lTimeSinceLastActivityNotif ;
    void NotifyActivity(tActivityStatus ActivityStatus) ;

    HANDLE m_hMonitorActivityTh;
    HANDLE m_hChanelIdleEv;
    HANDLE m_hChanelBusyEv ;
    friend DWORD WINAPI MonitorActivityTh( PVOID pContext ) ;

    // COM driver interface
    //----------------------
    DCB m_dcb ;
    COMMTIMEOUTS m_CommTimeouts ;

    DWORD m_ModemStatus;

    DWORD GetRxBytesAvailable() ;
    DWORD ReadData (BYTE *pInBuf, DWORD dwLen);

    friend DWORD COM_Init(LPCTSTR pContext, LPCVOID lpvBusContext) ;
    friend BOOL COM_Deinit(DWORD dwData) ;

    friend DWORD COM_Open(DWORD dwData, DWORD dwAccess, DWORD dwShareMode) ;
    friend BOOL COM_Close(DWORD dwOpenData) ;

    friend DWORD COM_Read(DWORD dwOpenData, LPVOID pBuf, DWORD len) ;
    friend DWORD COM_Write(DWORD dwOpenData, LPCVOID pBuf, DWORD len) ;
    friend DWORD COM_Seek(DWORD dwOpenData, long pos, DWORD type) ;

    friend void COM_PowerDown(DWORD dwData) ;
    friend void COM_PowerUp(DWORD dwData) ;

    friend BOOL COM_IOControl(DWORD dwOpenData, DWORD dwCode, PBYTE pBufIn, DWORD dwLenIn, PBYTE pBufOut, DWORD dwLenOut, 
                                PDWORD pdwActualOut) ;

} ;

//====================================================================================================
// Control Channel Class
//====================================================================================================

#define CTRL_UIH_PN             0x80        // DLC parameter negotiation
#define CTRL_UIH_PSC            0x40        // power saving control
#define CTRL_UIH_CLD            0xC0        // multiplexer close down
#define CTRL_UIH_TEST           0x20        // test
#define CTRL_UIH_FCON           0xA0        // flow control on command
#define CTRL_UIH_FCOFF          0x60        // flow control off command
#define CTRL_UIH_MSC            0xE0        // modem status command
#define CTRL_UIH_NSC            0x10        // non supported command response
#define CTRL_UIH_RPN            0x90        // remote port negocition command
#define CTRL_UIH_RLS            0x50        // remote line status command
#define CTRL_UIH_SNC            0xD0        // service negociation command

#define CTRL_SNC_MSG_LENGTH     3
#define CTRL_UIH_SNC_VOICE      0x04
#define CTRL_UIH_SNC_DATA       0x02

#define CTRL_MSC_MSG_LENGTH     2
#define CTRL_MSC_FC_BIT         0x02
#define CTRL_MSC_DSR_BIT        0x04
#define CTRL_MSC_CTS_BIT        0x08            
#define CTRL_MSC_RI_BIT         0x40    
#define CTRL_MSC_DCD_BIT        0x80        
#define CTRL_MSC_MS_STATUS      (CTRL_MSC_DSR_BIT | CTRL_MSC_CTS_BIT | CTRL_MSC_DCD_BIT)

#define CTRL_MAX_MSG_DATA       64

typedef struct
{
    BYTE  bType;
    DWORD cbData;
    BYTE  Data[CTRL_MAX_MSG_DATA];

} tCtrlMsg;

class CCtrlChanel : public CChanel
{
public :
    CCtrlChanel(BYTE bDlci) ;
    ~CCtrlChanel() ;

    bool Init() ;

    // GSM 07.10 commands
    bool NegotiateService(BYTE bDlci) ;
    bool SendModemStatus(BYTE bDlci, BYTE v24Sig) ;
    bool EnterPowerSavingMode() ;

protected:
    void SignalData();

private:

    HANDLE m_hEndOfRspProcessing ;
    HANDLE m_hDataEv;

    // init/terminate
    //----------------
    friend bool CtrlChnlTerminate(PVOID lpParameter) ;

    // GSM 07.10
    //-----------
    bool GetNextCtrlMsg(tCtrlMsg* pMsg);
    bool ParseUIH() ;

    // Command management
    tCtrlMsg m_CurCmd;    

    CRITICAL_SECTION m_csCommandLocker;
    CRITICAL_SECTION m_csPSCNegotiation ;

    // protocol thread
    friend DWORD WINAPI CtrlChannelTh( PVOID pContext ) ;
} ;
